#include "mapcanvas.h"
#include <QPainter>
#include <QMouseEvent>
#include <QUuid>
#include <QFile>
#include <QJsonDocument>
#include <QJsonObject>
#include <QJsonArray>
#include <QInputDialog>
#include <cmath>
#include <QtMath>
#include <QPolygonF>
#include "BezierInserter.h"
#include "onlinetileloader.h"

/* 角度阈值（度） */
static const qreal ANGLE_THRESH = 30.0;
#ifndef M_PI
#define M_PI 3.14159265358979323846
#endif
using std::acos;

/* 通用取名函数 */
static QString askFeatureName(QWidget *parent, const QString &defaultName)
{
    bool ok = false;
    QString text = QInputDialog::getText(parent,
                                         QObject::tr("命名"),
                                         QObject::tr("请输入图形名称："),
                                         QLineEdit::Normal,
                                         defaultName,
                                         &ok);
    return ok ? text : defaultName;
}

MapCanvas::MapCanvas(QWidget *parent) : QWidget(parent)
{
    setMouseTracking(true);
    setFocusPolicy(Qt::StrongFocus);
    m_cfg.load();
    m_centerLL = QPointF(m_cfg.lon0, m_cfg.lat0);
    // 在 MapCanvas 构造函数
    m_loader = new TileLoader("./tiles", this);
    m_centerLL = QPointF(121.490, 31.240);
    m_zoom     = 17;
    update();
//    // 构造函数
//    m_online = new m_urlTpl(
//        "http://webst02.is.autonavi.com/appmaptile?style=6&x={x}&y={y}&z={z}", this);
}

/* ---------- 绘制 ---------- */
void MapCanvas::paintEvent(QPaintEvent *)
{
    QPainter p(this);
    p.setRenderHint(QPainter::SmoothPixmapTransform);
    updateTransform();      // 每次重绘前更新矩阵
    drawTiles(p);           // 瓦片铺满
    drawFeatures(p);        // 用户图形
//    drawTiles(p);            // 1. 先画瓦片
//    p.fillRect(rect(), Qt::white);               // 底图占位
//    for (const Feature &f : m_feats) {
//        if (f.type == GeomType::Point) {
//            QPointF pt = f.vtx.first().p;
//            p.setPen(Qt::NoPen);
//            p.setBrush(Qt::red);
//            p.drawEllipse(pt, 5, 5);
//        } else if (f.type == GeomType::LineString || f.type == GeomType::Polygon) {
//            QPolygonF poly;
//            for (const Vertex &v : f.vtx) poly << v.p;
//            if (f.type == GeomType::LineString) {
//                p.setPen(QPen(Qt::blue, 2));
//                p.drawPolyline(poly);
//            } else {
//                p.setPen(QPen(Qt::darkGreen, 1));
//                p.setBrush(QColor(0, 200, 0, 70));
//                p.drawPolygon(poly);
//            }

//            /* 2. 在图形中心写名称 */
//            if (!f.name.isEmpty()) {
//                QPointF center;
//                if (f.type == GeomType::Point) {
//                    center = f.vtx.first().p;
//                } else {
//                    // 多边形/折线取包围盒中心
//                    QPolygonF poly;
//                    for (const Vertex &vx : f.vtx)
//                        poly << vx.p;
//                    QRectF br = poly.boundingRect();
////                    QRectF br;
//                    for (const Vertex &vx : f.vtx)
//                        br |= QRectF(vx.p, QSizeF(1,1));   // 构造包围盒
//                    center = br.center();
//                }
//                p.setPen(Qt::black);
//                p.drawText(center + QPointF(8,4), f.name);
//            }

//            // 节点
//            for (const Vertex &v : f.vtx) {
//                p.setBrush(v.selected ? Qt::red : Qt::green);
//                p.drawEllipse(v.p, 4, 4);
////                if (!v.name.isEmpty()) {
////                    p.setPen(Qt::black);
////                    p.drawText(v.p + QPointF(8,4), v.name);
////                }
//            }
//        }
//    }

}

/* ---------- 命中测试 ---------- */
static bool hit(const QPointF &pt, const QPointF &v, qreal tol = 8.0)
{ return QLineF(pt, v).length() < tol; }

/* ---------- 鼠标事件 ---------- */
void MapCanvas::mousePressEvent(QMouseEvent *e)
{
    if (e->button() != Qt::LeftButton) return;

    if (m_tool == Select) {
        m_featIdx = -1;
        qreal best = 10.0;
        for (int i = 0; i < m_feats.size(); ++i) {
            const Feature &f = m_feats[i];
            if (f.type == GeomType::Point) continue;
            for (int j = 0; j < f.vtx.size(); ++j) {
                if (hit(e->pos(), f.vtx[j].p)) {
                    qreal d = QLineF(e->pos(), f.vtx[j].p).length();
                    if (d < best) { best = d; m_featIdx = i; m_vtxIdx = j; }
                }
            }
        }
        if (m_featIdx != -1) {
            m_dragging = true;
            setCursor(Qt::ClosedHandCursor);
            for (auto &ft : m_feats) for (auto &vx : ft.vtx) vx.selected = false;
            m_feats[m_featIdx].vtx[m_vtxIdx].selected = true;

            /* 方案 C 初始化方向 */
            m_lastPos = e->pos();
            m_hasLastDir = false;   // 第一次按下时无方向
            update();
            return;
        }
    }

    if (m_tool == AddPoint) {
        Feature f;
        f.id = QUuid::createUuid().toString();
        f.type = GeomType::Point;
        f.vtx.append(Vertex{e->pos(), false});
        f.name = askFeatureName(this, "point");
        m_feats << f;
        update();
    } else if (m_tool == AddLine || m_tool == AddPolygon) {
        if (m_feats.empty() || m_feats.back().type != (m_tool == AddLine ? GeomType::LineString : GeomType::Polygon)) {
            Feature f;
            f.id = QUuid::createUuid().toString();
            f.type = (m_tool == AddLine) ? GeomType::LineString : GeomType::Polygon;
            f.name = (m_tool == AddLine) ?askFeatureName(this, "line") : askFeatureName(this, "polygon");
            m_feats << f;
        }
        m_feats.back().vtx.append(Vertex{e->pos(), false});
        update();
    }
}

void MapCanvas::mouseMoveEvent(QMouseEvent *e)
{
    if (!m_dragging)
        return;

    Feature &f = m_feats[m_featIdx];
    VertexList &v = f.vtx;

    /* 1. 先把当前节点拖到鼠标位置 */
    v[m_vtxIdx].p = e->pos();

    /* 2. 只有非端点才检查是否需要插点 */
    if (m_vtxIdx > 0 && m_vtxIdx < v.size() - 1) {
        const QPointF &prev = v[m_vtxIdx - 1].p;
        const QPointF &next = v[m_vtxIdx + 1].p;

        /* 3. 用贝塞尔曲线法判断是否需要插入新节点 */
        if (shouldInsertBezier(prev, e->pos(), next, 60.0, 80.0)) {
            /* 4. 在投影垂足处插入中点（简单取中点即可） */
            QPointF mid = (prev + e->pos()) * 0.5;
            v.insert(m_vtxIdx + 1, Vertex{mid, true});
            m_vtxIdx += 1;   // 让新节点成为当前拖拽节点
//            /* ===== 弹出命名对话框 ===== */
//            bool ok = false;
//            QString text = QInputDialog::getText(this,
//                                                 tr("Node Name"),
//                                                 tr("Enter name for new node:"),
//                                                 QLineEdit::Normal,
//                                                 QString("Point %1").arg(m_vtxIdx),
//                                                 &ok);
//            if (ok && !text.isEmpty())
//                v[m_vtxIdx].name = text;
            /* ========================= */
        }
    }

    update();

//    /* 计算当前方向向量 */
//    QPointF curDir = e->pos() - m_lastPos;
//    qreal len = sqrt(curDir.x()*curDir.x() + curDir.y()*curDir.y());
//    if (len < 1e-3) return;         // 几乎没动
//    curDir /= len;                  // 单位化

//    bool shouldInsert = false;
//    if (!m_hasLastDir) {
//        // 第一次有方向，只记录
//        m_lastDir = curDir;
//        m_hasLastDir = true;
//    } else {
//        /* 夹角公式：θ = acos(v1·v2) */
//        qreal dot = m_lastDir.x()*curDir.x() + m_lastDir.y()*curDir.y();
//        dot = qBound(-1.0, dot, 1.0);
//        qreal angle = acos(dot) * 180.0 / M_PI; // 转度
//        shouldInsert = (angle > ANGLE_THRESH);
//    }

//    if (shouldInsert) {
//        /* 在 m_vtxIdx 与下一节点之间插入中点 */
//        int next = (m_vtxIdx + 1) % v.size();
//        QPointF mid = (v[m_vtxIdx].p + v[next].p) / 2.0;
//        v.insert(next, Vertex{mid, true});
//        m_vtxIdx = next;
//        m_hasLastDir = false;   // 重新等待方向
//    } else {
//        m_lastDir = curDir;     // 继续当前方向
//    }

//    m_lastPos = e->pos();
//    update();
}

void MapCanvas::mouseReleaseEvent(QMouseEvent *e)
{
    Q_UNUSED(e);
    if (m_dragging) {
        m_dragging = false;
        setCursor(Qt::ArrowCursor);
    }
}

/* ---------- GeoJSON 导出 ---------- */
static QJsonObject featureToJson(const Feature &f, const QRectF &view)
{
    QJsonObject feat;
    feat["type"] = "Feature";
//    // 构造 properties（包含节点名称）
//    QJsonObject props = QJsonObject::fromVariantMap(f.props);
//    for (int i = 0; i < f.vtx.size(); ++i) {
//        if (!f.vtx[i].name.isEmpty())
//            props[QString("name_%1").arg(i)] = f.vtx[i].name;
//    }
    /* 把 name 写进 properties */
    QJsonObject props = QJsonObject::fromVariantMap(f.props);
    if (!f.name.isEmpty())
        props["name"] = f.name;
    feat["properties"] = props;

    QJsonObject geom;
    QJsonArray coords;
    if (f.type == GeomType::Point) {
        geom["type"] = "Point";
        coords = {f.vtx.first().p.x(), f.vtx.first().p.y()};
    } else if (f.type == GeomType::LineString) {
        geom["type"] = "LineString";
        for (const Vertex &v : f.vtx)
            coords.append(QJsonArray{v.p.x(), v.p.y()});
    } else if (f.type == GeomType::Polygon) {
        geom["type"] = "Polygon";
        QJsonArray ring;
        for (const Vertex &v : f.vtx)
            ring.append(QJsonArray{v.p.x(), v.p.y()});
        coords.append(ring);
    }
    geom["coordinates"] = coords;
    feat["geometry"] = geom;
    return feat;
}

void MapCanvas::exportGeoJson(const QString &fileName)
{
//    QJsonArray features;
//    for (const Feature &f : m_feats)
//        features << featureToJson(f, rect());
//    QJsonObject fc{{"type","FeatureCollection"},{"features",features}};
//    QFile f(fileName);
//    if (f.open(QIODevice::WriteOnly))
//        f.write(QJsonDocument(fc).toJson());
    QJsonArray features;
    for (const Feature &f : m_feats) {
        QJsonObject feat;
        feat["type"] = "Feature";
        feat["properties"] = QJsonObject::fromVariantMap(f.props);
        feat["properties"].toObject()["name"] = f.name;

        QJsonObject geom;
        QJsonArray coords;

        if (f.type == GeomType::Point) {
            geom["type"] = "Point";
            QPointF ll = xyToLonLat(f.vtx.first().p);
            coords = { ll.x(), ll.y() };
        }
        else if (f.type == GeomType::LineString) {
            geom["type"] = "LineString";
            for (const Vertex &v : f.vtx) {
                QPointF ll = xyToLonLat(v.p);
                coords.append(QJsonArray{ ll.x(), ll.y() });
            }
        }
        else if (f.type == GeomType::Polygon) {
            geom["type"] = "Polygon";
            QJsonArray ring;
            for (const Vertex &v : f.vtx) {
                QPointF ll = xyToLonLat(v.p);
                ring.append(QJsonArray{ ll.x(), ll.y() });
            }
            coords.append(ring);
        }

        geom["coordinates"] = coords;
        feat["geometry"] = geom;
        features.append(feat);
    }

    QJsonObject fc{{"type","FeatureCollection"},{"features",features}};
    QFile f(fileName);
    if (f.open(QIODevice::WriteOnly))
        f.write(QJsonDocument(fc).toJson());
}
/* 经纬度 → 屏幕 */
QPointF MapCanvas::lonLatToXy(double lon, double lat) const {
    double dx = (lon - m_cfg.lon0) * m_cfg.ppd;
    double dy = (m_cfg.lat0 - lat)  * m_cfg.ppd; // y 轴向下
    return QPointF(dx + width()/2.0, dy + height()/2.0);
}

/* 屏幕 → 经纬度 */
QPointF MapCanvas::xyToLonLat(const QPointF &xy) const {
    double dx = xy.x() - width()/2.0;
    double dy = xy.y() - height()/2.0;
    return QPointF(
        m_cfg.lon0 + dx / m_cfg.ppd,
        m_cfg.lat0 - dy / m_cfg.ppd
    );
}

void MapCanvas::loadGeoJson(const QString &fileName) {
    QFile f(fileName);
    if (!f.open(QIODevice::ReadOnly)) return;

    QJsonDocument doc = QJsonDocument::fromJson(f.readAll());
    QJsonObject fc = doc.object();
    QJsonArray feats = fc["features"].toArray();

    m_feats.clear();
    for (const QJsonValue &v : feats) {
        QJsonObject obj = v.toObject();
        Feature ft;
        ft.id   = obj["id"].toString();
        ft.name = obj["properties"].toObject()["name"].toString();

        QJsonObject geom = obj["geometry"].toObject();
        QString typeStr  = geom["type"].toString();
        if (typeStr == "Point") {
            ft.type = GeomType::Point;
            QJsonArray c = geom["coordinates"].toArray();
            QPointF ll(c[0].toDouble(), c[1].toDouble());
            ft.vtx.append(Vertex{lonLatToXy(ll.x(), ll.y()), false});
        }
        else if (typeStr == "LineString") {
            ft.type = GeomType::LineString;
            QJsonArray coords = geom["coordinates"].toArray();
            for (const QJsonValue &c : coords) {
                QJsonArray pt = c.toArray();
                QPointF ll(pt[0].toDouble(), pt[1].toDouble());
                ft.vtx.append(Vertex{lonLatToXy(ll.x(), ll.y()), false});
            }
        }
        else if (typeStr == "Polygon") {
            ft.type = GeomType::Polygon;
            QJsonArray rings = geom["coordinates"].toArray();
            if (!rings.isEmpty()) {
                QJsonArray coords = rings.first().toArray();
                for (const QJsonValue &c : coords) {
                    QJsonArray pt = c.toArray();
                    QPointF ll(pt[0].toDouble(), pt[1].toDouble());
                    ft.vtx.append(Vertex{lonLatToXy(ll.x(), ll.y()), false});
                }
            }
        }
        m_feats << ft;
    }
    update();
}

void MapCanvas::drawTiles(QPainter &p)
{
    const double tileSize = 256.0;
    const int z = m_zoom;
    QPointF topLeftTile = m_T.inverted().map(QPointF(0,0));
    QPointF bottomRightTile = m_T.inverted().map(QPointF(width(),height()));
    int x0 = qFloor(topLeftTile.x());
    int y0 = qFloor(topLeftTile.y());
    int x1 = qCeil(bottomRightTile.x());
    int y1 = qCeil(bottomRightTile.y());

    for (int y = y0; y < y1; ++y) {
        for (int x = x0; x < x1; ++x) {
            QPixmap pix = m_loader->getTile(z, x, y);
            if (!pix.isNull()) {
                QPointF pos = m_T.map(QPointF(x, y));
                p.drawPixmap(pos, pix);
            }
            if (pix.isNull()) {
                QPointF pos = m_T.map(QPointF(x, y));
                p.setBrush(QBrush(Qt::red));
                p.drawRect(QRectF(pos, QSizeF(256,256)));  // 红块==瓦片缺失
            }
        }
    }

//    if (!m_loader) return;

//    // 当前视图对应的瓦片范围
//    int z = m_zoom;
//    double tileSize = 256.0;
//    /* 计算当前视图中心对应的瓦片行列 */
//    QPointF centerTile = lonLatToTile(m_cfg.lon0, m_cfg.lat0, z);

//    /* 取 3×3 瓦片覆盖窗口（可扩展为动态范围） */
//    const int cx = static_cast<int>(centerTile.x());
//    const int cy = static_cast<int>(centerTile.y());
//    for (int dy = -1; dy <= 1; ++dy) {
//        for (int dx = -1; dx <= 1; ++dx) {
//            const int tx = cx + dx;
//            const int ty = cy + dy;

//            /* 内存缓存 key */
//            quint64 key = (quint64(z) << 40) | (quint64(tx) << 20) | quint64(ty);
//            if (QPixmap *cached = m_tileCache.object(key)) {
//                /* 缓存命中：直接绘制 */
//                QPointF topLeft((tx - centerTile.x()) * tileSize + width() / 2.0,
//                                (ty - centerTile.y()) * tileSize + height() / 2.0);
//                p.drawPixmap(topLeft, *cached);
//                continue;
//            }

//            /* 缓存未命中：异步下载 */
//            QString url = m_urlTpl.arg(tx).arg(ty).arg(z);
//            QNetworkRequest req(url);
//            QNetworkReply *reply = m_netMgr.get(req);
//            connect(reply, &QNetworkReply::finished,
//                    this, [this, reply, z, tx, ty, key] {
//                if (reply->error() == QNetworkReply::NoError) {
//                    QPixmap *pix = new QPixmap;
//                    pix->loadFromData(reply->readAll());
//                    m_tileCache.insert(key, pix);
//                }
//                reply->deleteLater();
//                update();                // 触发重绘
//            });
//        }
//    }
//    // 取 3×3 瓦片足够覆盖窗口
//    int cx = qFloor(centerTile.x());
//    int cy = qFloor(centerTile.y());
//    for (int dy = -1; dy <= 1; ++dy) {
//        for (int dx = -1; dx <= 1; ++dx) {
//            int tx = cx + dx;
//            int ty = cy + dy;
//            QPixmap tile = m_loader->getTile(z, tx, ty);
//            if (tile.isNull()) continue;

//            // 瓦片左上角像素坐标
//            QPointF topLeft((tx - centerTile.x()) * tileSize + width()/2.0,
//                            (ty - centerTile.y()) * tileSize + height()/2.0);
//            p.drawPixmap(topLeft, tile);
//        }
//    }
}

/* 绘制用户图形（使用同一矩阵） */
void MapCanvas::drawFeatures(QPainter &p) {
    /* 画一个 100×100 像素的蓝矩形，确保绘制流程 OK */
    p.resetTransform();  // 回到屏幕坐标
    p.setBrush(Qt::blue);
    p.drawRect(QRect(50, 50, 100, 100));
    p.setWorldTransform(m_T);   // 让坐标直接以瓦片行列绘制
    for (const Feature &f : m_feats) {
        if (f.type == GeomType::Point) {
            p.setBrush(Qt::red);
            p.drawEllipse(f.vtx.first().p, 0.01, 0.01); // 单位是度，放大后仍可见
        } else if (f.type == GeomType::LineString) {
            QPolygonF poly;
            for (const Vertex &v : f.vtx) poly << v.p;
            p.setPen(QPen(Qt::blue, 0.002));
            p.drawPolyline(poly);
        } else if (f.type == GeomType::Polygon) {
            QPolygonF poly;
            for (const Vertex &v : f.vtx) poly << v.p;
            p.setPen(QPen(Qt::darkGreen, 0.001));
            p.setBrush(QColor(0,200,0,60));
            p.drawPolygon(poly);
        }
    }
}

QPointF MapCanvas::lonLatToTile(double lon, double lat, int z) const {
    const double n = pow(2.0, z);
    double x = (lon + 180.0) / 360.0 * n;
    double y = (1.0 - log(tan(lat * M_PI/180.0) + 1.0/cos(lat * M_PI/180.0)) / M_PI) / 2.0 * n;
    return QPointF(x, y);
}
/* 计算当前缩放矩阵（每次 zoom 或 resize 调用） */
void MapCanvas::updateTransform() {
    double tileSize = 256.0;
    QPointF centerTile = lonLatToTile(m_centerLL.x(), m_centerLL.y(), m_zoom);
    double cx = width()  / 2.0 - centerTile.x() * tileSize;
    double cy = height() / 2.0 - centerTile.y() * tileSize;
    m_T = QTransform::fromTranslate(cx, cy).scale(tileSize, tileSize);
}

/* 经纬度 → 屏幕像素 */
QPointF MapCanvas::lonLatToScreen(const QPointF &ll) const {
    const double tileSize = 256.0;
    QPointF tile = lonLatToTile(ll.x(), ll.y(), m_zoom);
    QPointF centerTile = lonLatToTile(m_centerLL.x(), m_centerLL.y(), m_zoom);
    return QPointF(
        width()  / 2.0 + (tile.x() - centerTile.x()) * tileSize,
        height() / 2.0 + (tile.y() - centerTile.y()) * tileSize);
}
/* 瓦片行列 → 经纬度（墨卡托反算） */
QPointF MapCanvas::tileToLonLat(double tx, double ty, int z) const
{
    const double n = std::pow(2.0, z);
    const double lon = tx / n * 360.0 - 180.0;
    const double latRad = std::atan(std::sinh(M_PI * (1.0 - 2.0 * ty / n)));
    const double lat = latRad * 180.0 / M_PI;
    return QPointF(lon, lat);
}
/* 屏幕像素 → 经纬度 */
QPointF MapCanvas::screenToLonLat(const QPointF &xy) const {
    const double tileSize = 256.0;
    QPointF centerTile = lonLatToTile(m_centerLL.x(), m_centerLL.y(), m_zoom);
    QPointF tile(
        centerTile.x() + (xy.x() - width()/2.0) / tileSize,
        centerTile.y() + (xy.y() - height()/2.0) / tileSize);
    return tileToLonLat(tile.x(), tile.y(), m_zoom);
}
// 在 MapCanvas 里加 setZoom
void MapCanvas::setZoom(int z) {
    m_zoom = qBound(3, z, 19);
    update();
}

int MapCanvas::zoom() {
    return m_zoom;
}
